package ren.shinelong.config;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
@Component
@Primary
@AllArgsConstructor
public class SwaggerResourceConfig implements SwaggerResourcesProvider {

	/**
	 * swagger2默认的url后缀
	 */
	private static final String SWAGGER2URL = "/v2/api-docs";

	/**
	 * 路由加载器
	 */
	private final RouteLocator routeLocator;

	/**
	 * 网关应用名称
	 */
	@Value("${spring.application.name}")
	private String gateway;

	@Autowired
	public SwaggerResourceConfig(RouteLocator routeLocator) {
		this.routeLocator = routeLocator;
	}

	@Override
	public List<SwaggerResource> get() {
		List<SwaggerResource> resources = new ArrayList<>();
		List<String> routeHosts = new ArrayList<>();
		Flux<Route> routes = this.routeLocator.getRoutes();
		// 获取所有可用的host,因为是注册表服务调用,所以实际是服务名
		routes.filter(route -> route.getUri().getHost() != null)
				.filter(route -> !this.gateway.equals(route.getUri().getHost()))
				.subscribe(route -> routeHosts.add(route.getUri().getHost()));

		// 去重下拉列表相同服务名文档,多个服务展示一个,当网关调用这个接口时，会自动通过负载均衡寻找服务host
		Set<String> docServerSet = new HashSet<>();
		routeHosts.forEach(instance -> {
			// 拼接url. /serviceId/v2/api-info
			String url = "/" + instance + SwaggerResourceConfig.SWAGGER2URL;
			if (!docServerSet.contains(url)) {
				docServerSet.add(url);
				SwaggerResource swaggerResource = new SwaggerResource();
				swaggerResource.setUrl(url);
				swaggerResource.setName(instance);
				resources.add(swaggerResource);
			}
		});
		return resources;
	}
}